package com.kepler.social.domain.user.security;

import com.kepler.social.common.constants.CountryCallingCode;
import com.kepler.social.common.constants.Enums;
import com.kepler.social.common.constants.TipsConst;
import com.kepler.social.common.utils.DateTimeUtil;
import com.kepler.social.common.utils.Safes;
import com.kepler.social.common.utils.ValidateAssert;
import com.kepler.social.common.rule.SmsRule;
import com.kepler.social.usersecurity.dao.domain.UserEmail;
import com.kepler.social.usersecurity.dao.domain.UserMobilePhone;
import com.kepler.social.usersecurity.dao.domain.UserPassword;
import com.kepler.social.usersecurity.dao.mapper.UserEmailMapper;
import com.kepler.social.usersecurity.dao.mapper.UserMobilePhoneMapper;
import com.kepler.social.usersecurity.dao.mapper.UserPasswordMapper;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Repository
public class UserSecurityRepository {

    @Resource
    private UserEmailMapper userEmailMapper;
    @Resource
    private UserPasswordMapper userPasswordMapper;
    @Resource
    private UserMobilePhoneMapper userMobilePhoneMapper;

    public String findValidUserPassword(Long userId) {
        UserPassword userPassword = userPasswordMapper.selectByPrimaryKey(userId);
        ValidateAssert.notNull(userPassword, TipsConst.user_not_exists);
        return userPassword.getPassword();
    }

    public UserSecurityAggregate findByEmail(String email) {
        UserEmail userEmail = userEmailMapper.selectByPrimaryKey(email);
        if (Objects.isNull(userEmail)) {
            return new UserSecurityAggregate(null, (UserEmail) null);
        }
        return new UserSecurityAggregate(userPasswordMapper.selectByPrimaryKey(userEmail.getUserId()), userEmail);
    }

    public UserSecurityAggregate findByMobilePhone(Long mobilePhoneNumber) {
        return findByMobilePhone(CountryCallingCode.China.code, mobilePhoneNumber);
    }

    /**
     * 这段代码的修改和DDD有关系，之前是设置了状态未有用，直接单查出来。但是这样的话，生成的聚合根就不能正确反应现实。因为从业务设计上，废弃大的手机
     * 号码才等同于不存在。未验证，应当算存在。否则有一些聚合根的方法调用，就不正确。比如，这个手机号码是否待验证。
     *
     * @param countryCallingCode
     * @param mobilePhoneNumber
     * @return
     */
    public UserSecurityAggregate findByMobilePhone(Integer countryCallingCode, Long mobilePhoneNumber) {
        assert SmsRule.isCccValid(countryCallingCode);
        List<UserMobilePhone> phones = userMobilePhoneMapper.selectByPhoneNumber(countryCallingCode, mobilePhoneNumber);
        phones = Safes.of(phones).stream()
                .filter(phone -> Enums.UserMobilePhoneStateEnum.DISUSED.code != phone.getState())
                .collect(Collectors.toList());
        ValidateAssert.isTrue(phones.size() <= 1, TipsConst.system_error_multi_result);
        if (CollectionUtils.isEmpty(phones)) {
            return new UserSecurityAggregate(null, (UserMobilePhone) null);
        }
        UserMobilePhone phone = phones.get(0);
        return new UserSecurityAggregate(userPasswordMapper.selectByPrimaryKey(phone.getUserId()), phone);
    }

    public void create(UserSecurityAggregate aggregate) {
        userPasswordMapper.insert(aggregate.getRoot());
        if (Objects.nonNull(aggregate.getEmail())) {
            userEmailMapper.insert(aggregate.getEmail());
        }
        if (Objects.nonNull(aggregate.getPhone())) {
            userMobilePhoneMapper.insert(aggregate.getPhone());
        }
    }

    public void updateMobileState(UserSecurityAggregate aggregate, Enums.UserMobilePhoneStateEnum state) {
        aggregate.isMobilePhoneExist();
        UserMobilePhone phone = aggregate.getPhone();
        phone.setState(state.getCode());
        userMobilePhoneMapper.updateStateById(phone.getId(), phone.getPhoneNumber(), phone.getState(),
                DateTimeUtil.toMilli(LocalDateTime.now()));
    }

    public void updateEmailState(UserSecurityAggregate aggregate, Enums.UserEmailStateEnum state) {
        aggregate.isEmailExist();
        aggregate.getEmail().setState(state.getCode());
        userEmailMapper.updateByPrimaryKey(aggregate.getEmail());
    }

    public void updatePassword(UserSecurityAggregate aggregate, String encodePassword) {
        UserPassword aggregateRoot = aggregate.getRoot();
        aggregateRoot.setPassword(encodePassword);
        aggregateRoot.setModifiedTime(DateTimeUtil.toMilli(LocalDateTime.now()));
        userPasswordMapper.updateByPrimaryKey(aggregateRoot);
    }

    public void updatePassword(Long userId, String encodePassword) {
        UserPassword userPassword = userPasswordMapper.selectByPrimaryKey(userId);
        userPassword.setPassword(encodePassword);
        userPassword.setModifiedTime(DateTimeUtil.toMilli(LocalDateTime.now()));
        userPasswordMapper.updateByPrimaryKey(userPassword);
    }


}
